﻿using System;
using System.Net.Sockets;
using System.Threading;
using ZhangLogSysV1d0;

namespace EscPrinterHelperV1d0.Service
{
    /// <summary>
    /// 使用线程实现套接字连接服务器的帮助类
    /// </summary>
    public class ThreadTcpClientConnectServerHelperV1d0
    {
        /// <summary>
        ///tcp连接状态改变事件，或者连接成功或者连接失败或超时
        /// </summary>
        public event EventHandler<TcpClient> ConnectStatusChangedEvent;
        /// <summary>
        /// 是否运行
        /// </summary>
        private bool Running;

        /// <summary>
        /// IP地址
        /// </summary>
        public string PrinterIp { get; set; }
        /// <summary>
        /// 端口
        /// </summary>
        public int PrinterPort { get; set; }
        /// <summary>
        /// 连接超时时长
        /// </summary>
        public int ConnnectTimeOutMilliSecond { get; set; }

        private object PrinterTcpClientLock = new object();
        private TcpClient _PrinterTcpClient = null;
        public TcpClient PrinterTcpClient
        {
            get
            {
                lock (PrinterTcpClientLock)
                {
                    return _PrinterTcpClient;
                }
            }
            set
            {
                lock (PrinterTcpClientLock)
                {
                    _PrinterTcpClient = value;
                }
            }
        }
        public bool IsConnectionSuccessful = false;
        private object IsConnectedLock = new object();
        private bool _IsConnected = false;
        public bool IsConnected
        {
            get
            {
                lock (IsConnectedLock)
                {
                    return _IsConnected;
                }
            }
            set
            {
                lock (IsConnectedLock)
                {
                    _IsConnected = value;
                }
            }
        }
        private ManualResetEvent TimeoutObject = new ManualResetEvent(false);

        /// <summary>
        /// 连接线程
        /// </summary>
        private Thread ThreadTcpConnecting = null;
        /// <summary>
        /// 线程序号
        /// </summary>
        public int ThreadIndex { get; set; }

        public ThreadTcpClientConnectServerHelperV1d0()
        {
            Running = false;
            PrinterIp = "127.0.0.1";
            PrinterPort = 9100;
            PrinterTcpClient = null;
            IsConnectionSuccessful = false;
            IsConnectedLock = new object();
            IsConnected = false;
            TimeoutObject = new ManualResetEvent(false);
            PrinterTcpClientLock = new object();
            ThreadTcpConnecting = null;
            ThreadIndex = 0;
            ConnnectTimeOutMilliSecond = 1000;
        }
        public ThreadTcpClientConnectServerHelperV1d0(string printerIp,int printerPort)
        {
            Running = false;
            PrinterIp = printerIp;
            PrinterPort = printerPort;
            PrinterTcpClient = null;
            IsConnectionSuccessful = false;
            IsConnectedLock = new object();
            IsConnected = false;
            TimeoutObject = new ManualResetEvent(false);
            PrinterTcpClientLock = new object();
            ThreadTcpConnecting = null;
            ThreadIndex = 0;
            ConnnectTimeOutMilliSecond = 1000;

        }
        /// <summary>
        /// 启动线程
        /// </summary>
        public void StartThread()
        {
            this.ThreadTcpConnecting = new Thread(new System.Threading.ThreadStart(this.ThreadStart));
            this.Running = true;
            //作为后台线程
            this.ThreadTcpConnecting.IsBackground = false;
            //启动线程
            this.ThreadTcpConnecting.Start();
        }
        /// <summary>
        /// 停止线程
        /// </summary>
        public void StopThread()
        {
            this.Running = false;
        }

        /// <summary>
        /// 线程启动
        /// </summary>
        private void ThreadStart()
        {
            while (Running)
            {
                try
                {
                    if (!IsConnected)
                    {
                        PrinterTcpClient = TryConnect(PrinterIp, PrinterPort, ConnnectTimeOutMilliSecond);
                        if(IsConnected)
                        {
                            //如果连接成功，发出连接成功事件
                            if (ConnectStatusChangedEvent != null) ConnectStatusChangedEvent(this, PrinterTcpClient);
                        }
                    }
                }
                catch (Exception ex)
                {
                    //异常，或者连接超时，就继续尝试连接
                    IsConnected = false;
                    continue;
                }
                //比连接超时时间稍长
                Thread.Sleep(ConnnectTimeOutMilliSecond+100);
            }
        }
        /// <summary>
        /// 连接尝试
        /// </summary>
        /// <param name="serverIp"></param>
        /// <param name="serverPort"></param>
        /// <param name="timeoutMiliSecond">超时时常</param>
        /// <returns></returns>
        public TcpClient TryConnect(string serverIp, int serverPort, int timeoutMiliSecond=1000)
        {
            //信号关门
            TimeoutObject.Reset();
            TcpClient currTcpClient = new TcpClient();
            try
            {
                //设定发数据的超时时间
                currTcpClient.SendTimeout = 1000;
                currTcpClient.BeginConnect(serverIp, serverPort, new AsyncCallback(CallBackMethod), currTcpClient);
                //等待信号timeoutMiliSecond事件若干秒，
                if (TimeoutObject.WaitOne(timeoutMiliSecond, false))
                {
                    if (IsConnected)
                    {
                        return currTcpClient;
                    }
                    else
                    {
                        //如果未连接也抛出异常
                        throw new Exception("Connnected Failed");
                    }
                }
                else
                {
                    //若超时，则关闭tpclient，发出超时异常
                    IsConnectionSuccessful = false;
                    currTcpClient.Close();
                    throw new TimeoutException("TimeOut Exception");
                }
            }
            catch (Exception ex)
            {
                SimpleLoger.Instance.Error(ex);
            }
            return currTcpClient;
        }
        /// <summary>
        /// 异步连接的回调函数
        /// </summary>
        /// <param name="asyncresult"></param>
        private void CallBackMethod(IAsyncResult asyncresult)
        {
            try
            {
                IsConnected = false;
                TcpClient tcpClient = asyncresult.AsyncState as TcpClient;
                if (tcpClient.Client != null)
                {
                    tcpClient.EndConnect(asyncresult);
                    IsConnected = true;
                }
            }
            catch (Exception ex)
            {
                IsConnected = false;
            }
            finally
            {
                //连接到服务器，或者异常时，信号开门 线程继续运行
                TimeoutObject.Set();
            }
        }
    }
}
